﻿using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.X509;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Una.FirmaDigital.EN;

namespace Una.FirmaDigital.LN.Dominio.Especificaciones
{
    public class Firma
    {
        public bool FirmaDesacopladaBasica(string filesrc, string contrasena, string motivo,
            string pfxsrc, string filedes, bool abrirarchivo, ref string mensaje)
        {
            try
            {
                Validaciones.Firma validacionesfirma = new Validaciones.Firma();
                Acciones.Firma accionesfirma = new Acciones.Firma();
                if (!validacionesfirma.ExisteArchivo(filesrc)
                    || !validacionesfirma.ExisteArchivo(pfxsrc)
                    || !validacionesfirma.ExisteDirectorio(filedes))
                {
                    return false;
                }
                else
                {
                    string archivodestino = accionesfirma.obtenerNombreArchivo(filesrc, ref mensaje);
                    FileStream privateKeyStream = accionesfirma.obtenerStreamDesdeSrcopen(pfxsrc, ref mensaje);
                    Pkcs12Store pk12 = accionesfirma.obtenerPkcsStore(privateKeyStream, contrasena, ref mensaje);
                    string aliasresult = "";
                    foreach (string tAlias in pk12.Aliases)
                    {

                        if (pk12.IsKeyEntry(tAlias))
                        {
                            aliasresult = tAlias;
                            //obtenemos la llave privada de lo que es el certificado.
                            break;
                        }

                    }
                    privateKeyStream.Dispose();
                    //llave privada
                    var llaveprivada = pk12.GetKey(aliasresult).Key;

                    //crear el stream
                    // FileStream fileoriginstream = new FileStream("prueba4sig2.pdf", FileMode.Open, FileAccess.Read);
                    //obtenermos el hash del documento
                    //  string hashfile = ObtenerCodigoHash(fileoriginstream); Console.WriteLine("hash {0}", hashfile);
                    //el documenot a firmar obtenido del stream
                    PdfReader documentoorigen = accionesfirma.obtenerPdfdeSrc(filesrc, ref mensaje);
                    string newfile = (filedes + "\\" + archivodestino);
                    Console.WriteLine(newfile);

                    using (FileStream fout = accionesfirma.obtenerStreamDesdeSrccreate((newfile), ref mensaje))
                    {

                        using (PdfStamper stamper = PdfStamper.CreateSignature(documentoorigen, fout, '\0', null, true))
                        {
                            //este paso es opcional... seria interesante tomar un booleano e indicar que si el usuario quiere o no encriptar.
                            //   stamper.SetEncryption(new X509Certificate[] { pk12.GetCertificate(aliasresult).Certificate }, new int[] { PdfWriter.ALLOW_SCREENREADERS }, PdfWriter.ENCRYPTION_AES_128);
                            PdfSignatureAppearance apper = stamper.SignatureAppearance;

                            apper.Reason = motivo;

                            iTextSharp.text.pdf.security.IExternalSignature es = new iTextSharp.text.pdf.security.PrivateKeySignature(llaveprivada, "SHA-256");
                            accionesfirma.FirmarDesacopladoBasico(apper, es, new X509Certificate[] { pk12.GetCertificate(aliasresult).Certificate }, null, null, null, 0, CryptoStandard.CMS, ref mensaje);

                            stamper.Close();

                        }
                    }
                    if (abrirarchivo)
                    {
                        System.Diagnostics.Process.Start(newfile);
                    }
                    mensaje = "Correcto";
                }
            }
            catch (Exception ex)
            {
                mensaje += ex.Message + ex.StackTrace;
                return false;
            }

            return true;
        }


        public List<Una.FirmaDigital.EN.Respuesta> VerificarPdf(string filesrc, ref string mensaje)
        {
            List<Una.FirmaDigital.EN.Respuesta> respuestas = new List<Una.FirmaDigital.EN.Respuesta>();
            Validaciones.Firma validacionesfirma = new Validaciones.Firma();
            Acciones.Firma accionesfirma = new Acciones.Firma();
            try
            {
                if (!validacionesfirma.documentoTieneContrasena(filesrc))
                {

                    respuestas.Add(new Respuesta() { CodigoEstado = 1, Mensaje = "Documento no contiene contraseña" });

                    PdfReader archivopdf = accionesfirma.obtenerPdfdeSrc(filesrc, ref mensaje);

                    if (validacionesfirma.pdfTieneFirma(archivopdf))
                    {
                        respuestas.Add(new Respuesta() { CodigoEstado = 1, Mensaje = "Documento  contiene firmas registradas" });
                        if (validacionesfirma.firmaVerificadabasico(filesrc))
                        {
                            respuestas.Add(new Respuesta() { CodigoEstado = 1, Mensaje = "Documento  contiene firmas que se consideran válidas" });

                        }
                        else
                        {
                            respuestas.Add(new Respuesta() { CodigoEstado = 2, Mensaje = "Documento no contiene firmas válidas" });
                        }
                        if (validacionesfirma.tieneContraFirmas2(filesrc))
                        {
                            int numero = validacionesfirma.obtenerNumeroRevisionesDocumento(filesrc);
                            respuestas.Add(new Respuesta() { CodigoEstado = 1, Mensaje = "Documento  contiene " + numero + " contrafirmas registradas" });
                        }
                        else
                        {
                            respuestas.Add(new Respuesta() { CodigoEstado = 1, Mensaje = "Documento no contiene contrafirmas registradas" });
                        }
                        int numerovacios = validacionesfirma.obtenerNumeroFirmasVacias(filesrc);
                        if (numerovacios > 0)
                        {

                            respuestas.Add(new Respuesta() { CodigoEstado = 1, Mensaje = "Documento  contiene " + numerovacios + " firmas vacias" });
                        }
                        else
                        {
                            respuestas.Add(new Respuesta() { CodigoEstado = 1, Mensaje = "Documento no contiene firmas vacias" });
                        }

                        if (validacionesfirma.firmaTimeStampVerificada(filesrc))
                        {
                            int numero = validacionesfirma.obtenerNumeroRevisionesDocumento(filesrc);
                            respuestas.Add(new Respuesta() { CodigoEstado = 1, Mensaje = "Se verificó el Timestamp del documento" });
                        }
                        else
                        {
                            respuestas.Add(new Respuesta() { CodigoEstado = 2, Mensaje = "No se verificó el Timestamp del documento" });
                            respuestas.Add(new Respuesta() { CodigoEstado = 2, Mensaje = "La fecha y la hora provienen del equipo del firmante" });
                        }
                    }
                    else
                    {
                        respuestas.Add(new Respuesta() { CodigoEstado = 3, Mensaje = "Documento  no contiene firmas" });
                    }

                }
                else
                {
                    respuestas.Add(new Respuesta() { CodigoEstado = 1, Mensaje = "Documento  contiene contraseña y no se puede validar." });
                }



            }
            catch (Exception ex)
            {
                mensaje = ex.Message + ex.StackTrace;
                mensaje += "no se pudo validar";
                respuestas.Add(new Respuesta() { CodigoEstado = 1, Mensaje = "Documento no se completó" });
            }

            return respuestas;
        }


        public List<Una.FirmaDigital.EN.Respuesta> VerificarPdfContraLlavePublica(string filesrc, string cersrc, ref string mensaje)
        {
            List<Una.FirmaDigital.EN.Respuesta> respuestas = new List<Una.FirmaDigital.EN.Respuesta>();
            Validaciones.Firma validacionesfirma = new Validaciones.Firma();
            Acciones.Firma accionesfirma = new Acciones.Firma();
            try
            {
                if (!validacionesfirma.documentoTieneContrasena(filesrc))
                {

                    respuestas.Add(new Respuesta() { CodigoEstado = 1, Mensaje = "Documento no contiene contraseña" });

                    PdfReader archivopdf = accionesfirma.obtenerPdfdeSrc(filesrc, ref mensaje);

                    if (validacionesfirma.pdfTieneFirma(archivopdf))
                    {
                        respuestas.Add(new Respuesta() { CodigoEstado = 1, Mensaje = "Documento  contiene firmas registradas" });
                        if (validacionesfirma.firmaVerificadabasico(filesrc))
                        {
                            respuestas.Add(new Respuesta() { CodigoEstado = 1, Mensaje = "Documento  contiene firmas que se consideran válidas" });
                        }
                        else
                        {
                            respuestas.Add(new Respuesta() { CodigoEstado = 3, Mensaje = "Documento no contiene firmas válidas" });
                        }

                        if (validacionesfirma.documentoFirmadoCorrectobasico(filesrc, new FileStream(cersrc, FileMode.Open)))
                        {
                            respuestas.Add(new Respuesta() { CodigoEstado = 1, Mensaje = "Documento  contiene firmas validas contra la llave qeu se indicó" });
                        }
                        else
                        {
                            respuestas.Add(new Respuesta() { CodigoEstado = 3, Mensaje = "Documento no contiene firmas válidas con respecto a llave que se paso" });
                        }


                        if (validacionesfirma.tieneContraFirmas2(filesrc))
                        {
                            int numero = validacionesfirma.obtenerNumeroRevisionesDocumento(filesrc);
                            respuestas.Add(new Respuesta() { CodigoEstado = 4, Mensaje = "Documento  contiene " + numero + " contrafirmas registradas" });
                        }
                        else
                        {
                            respuestas.Add(new Respuesta() { CodigoEstado = 4, Mensaje = "Documento no contiene contrafirmas registradas" });
                        }
                        int numerovacios = validacionesfirma.obtenerNumeroFirmasVacias(filesrc);
                        if (numerovacios > 0)
                        {
                            respuestas.Add(new Respuesta() { CodigoEstado = 4, Mensaje = "Documento  contiene " + numerovacios + " firmas vacias" });
                        }
                        else
                        {
                            respuestas.Add(new Respuesta() { CodigoEstado = 4, Mensaje = "Documento no contiene firmas vacias" });
                        }

                        if (validacionesfirma.firmaTimeStampVerificada(filesrc))
                        {
                            int numero = validacionesfirma.obtenerNumeroRevisionesDocumento(filesrc);
                            respuestas.Add(new Respuesta() { CodigoEstado = 1, Mensaje = "Se verificó el Timestamp del documento" });
                        }
                        else
                        {
                            respuestas.Add(new Respuesta() { CodigoEstado = 2, Mensaje = "No se verificó el Timestamp del documento" });
                            respuestas.Add(new Respuesta() { CodigoEstado = 2, Mensaje = "La fecha y la hora provienen del equipo del firmante" });
                        }
                    }
                    else
                    {
                        respuestas.Add(new Respuesta() { CodigoEstado = 4, Mensaje = "Documento  no contiene firmas" });
                    }

                }
                else
                {
                    respuestas.Add(new Respuesta() { CodigoEstado = 3, Mensaje = "Documento  contiene contraseña y no se puede validar." });
                }


                mensaje = "Proceso Completado";
            }
            catch (Exception ex)
            {
                mensaje = ex.Message + ex.StackTrace;
                mensaje += "no se pudo validar";
                respuestas.Add(new Respuesta() { CodigoEstado = 3, Mensaje = "Documento no se completó" });
            }

            return respuestas;
        }
    }
}
